﻿using Chaotic.Core.Extension;
using Chaotic.DataBase.DBAccessLibrary.DBAccessLibrary;
using Chaotic.DataBase.DBAccessLibrary.Model;
using Chaotic.Module.DBTool.Models;
using Chaotic.Module.DBTool.Views;
using Prism.Dialogs;
using Prism.Events;
using System.Collections.ObjectModel;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Windows;

namespace Chaotic.Module.DBTool.ViewModels
{
    public class DBTreeContentViewModel : BindableBase
    {
        private readonly IEventAggregator _eventAggregator;
        private readonly IDBRabbionCommandMenu _rabbionCommandMenu;
        public DBTreeContentViewModel(IEventAggregator eventAggregator, IDBRabbionCommandMenu dBRabbionCommandMenu)
        {
            _eventAggregator = eventAggregator;
            _rabbionCommandMenu = dBRabbionCommandMenu;
            eventAggregator.ResgiterMessage<DBToolMessage>(message =>
            {
                if (message is { Target: nameof(DBTreeContentViewModel), ActionName: "Connection" })
                {
                    Connection();
                }
            });

            InitRabbionMenuCommand(dBRabbionCommandMenu);
            ConnectDBCommand = new DelegateCommand<DBEntity>(ChangeDBConnectionStatus, db=> DbConnectCanExecute( DBConnectStatus.Off)); 
            UnConnectDBCommand = new DelegateCommand<DBEntity>(delegate (DBEntity entity)
            {
                entity.Status = DBConnectStatus.Off;
                SelectedItem = entity;
            }, 
            db=> DbConnectCanExecute( DBConnectStatus.Connected));
            EditConnectDBCommand = new DelegateCommand<DBEntity>(delegate (DBEntity entity)
            {
                if (ShowRegister != null)
                {
                    ShowRegister(entity);
                }
            }, delegate
            {
                if (SelectedItem == null)
                {
                    return false;
                }

                return SelectedItem is DBEntity;
            });
            SelectAllCommand = new DelegateCommand<TableEntity>(delegate (TableEntity entity)
            {
                WriteSql(entity.SelectAll(), SqlControlStatus.NoRun | SqlControlStatus.NewLine);
            });
            SelectTopCommand = new DelegateCommand<TableEntity>(delegate (TableEntity entity)
            {
                WriteSql(entity.SelectTop(), SqlControlStatus.NoRun | SqlControlStatus.NewLine);
            });
            SelectRunCommand = new DelegateCommand<TableEntity>(delegate (TableEntity entity)
            {
                WriteSql(entity.SelectAll(), SqlControlStatus.Run | SqlControlStatus.NewLine);
            });
            CopyCommand = new DelegateCommand<DataBaseEntity>(delegate (DataBaseEntity entity)
            {
                try
                {
                    if (entity.TransName != null) 
                        Clipboard.SetText(entity.TransName);
                }
                catch
                {
                    // ignored
                }
            });
            ShowNewWindowCommand = new DelegateCommand<ViewEntity>(delegate (ViewEntity entity)
            {
            });
            DeleteCommand = new DelegateCommand<DataBaseEntity>(DeleteDbExcute, (entity) => SelectedItem is not null);
           
            ExprotTableStructureCommand = new DelegateCommand<TableEntity>(delegate (TableEntity entity)
            {
                if (SysCache.DBConnection != null)
                {
                    string? createInfo = DBOperatorFactory.GetGrammar(SysCache.DBConnection)?.GetCreateInfo(SysCache.DBConnection.ConnectType, entity);
                    WriteSql(createInfo,  SqlControlStatus.NewLine);
                }
            }, entity => SelectedItem is TableEntity);
            RefreshCommand = new DelegateCommand<DBEntity>(delegate
            {
                try
                {
                    Connection();
                }
                catch (Exception ex)
                {
                    WriteLog(ex.Message, 1);
                }
            });
            AddDescriptionCommand = new DelegateCommand<TableEntity>(delegate (TableEntity entity)
            {
                if (ShowDescriptionWindows != null)
                {
                    ShowDescriptionWindows(entity);
                }
            });
            ShowProcInfoCommand = new DelegateCommand<ProcEntity>(delegate (ProcEntity entity)
            {
                WriteSql(DBOperatorFactory.GetGrammar(SysCache.DBConnection)?.GetProcParamInfo(entity), SqlControlStatus.NoRun | SqlControlStatus.NewLine);
            });
            
            TableDefinitionCommand = new DelegateCommand<TableEntity>(delegate (TableEntity entity)
            {
                //表定义
                eventAggregator.SendMessage(new DBToolMessage
                {
                    Target = nameof(DBMasterContent),
                    ActionName = "AddTableDefinitionDocument",
                    Data = entity
                });
            });
            
        }

        private void InitRabbionMenuCommand(IDBRabbionCommandMenu dBRabbionCommandMenu)
        { 
            dBRabbionCommandMenu.DbConnectCommand = new DelegateCommand(() =>
            {
                if (SelectedItem is DBEntity dBEntity)
                {
                    ChangeDBConnectionStatus(dBEntity);
                }
            }, ()=>DbConnectCanExecute( DBConnectStatus.Off));
            dBRabbionCommandMenu.DbUnConnectCommand = new DelegateCommand(() =>
            {
                if (SelectedItem is DBEntity dBEntity)
                {
                    dBEntity.Status = DBConnectStatus.Off;
                }
            },()=> DbConnectCanExecute( DBConnectStatus.Connected));

            dBRabbionCommandMenu.RemoveDbCommand = new DelegateCommand(()=> DeleteDbExcute(SelectedItem), () => SelectedItem is not null);
        }
        //刷新菜单
        private void RefreshRabbionMenuCanExecuteChanged()
        {
            _rabbionCommandMenu.RemoveDbCommand.RaiseCanExecuteChanged();
            _rabbionCommandMenu.DbUnConnectCommand.RaiseCanExecuteChanged();
            _rabbionCommandMenu.DbConnectCommand.RaiseCanExecuteChanged();
        }
        #region command other 
        private bool DbConnectCanExecute(DBConnectStatus connectStatus)
        {
            if (SelectedItem == null)
            {
                return false;
            }

            return SelectedItem is DBEntity { ConnectionSource: not null } dBEntity3 && dBEntity3.Status == connectStatus;
        }

        private void DeleteDbExcute(DataBaseEntity? entity)
        {
            if (SysCache.ServerList == null || entity == null)
                return;

            DataBaseEntity? dataBaseEntity = SysCache.ServerList.FirstOrDefault(o =>o.ChildNodes.FirstOrDefault(p => p.Equals(entity)) != null);
            if (dataBaseEntity != null)
            {
                dataBaseEntity.ChildNodes?.Remove(entity);
            }
            else
            {
                dataBaseEntity = SysCache.ServerList.FirstOrDefault((o) => o.Equals(entity));
                if (dataBaseEntity != null)
                {
                    SysCache.ServerList.Remove(dataBaseEntity);
                }
            } 
            WriteData();

            //刷新菜单
            RefreshRabbionMenuCanExecuteChanged();
        }
        #endregion

        public DelegateCommand<DBEntity> ConnectDBCommand { get; set; }

        public DelegateCommand<DBEntity> UnConnectDBCommand { get; set; }

        public DelegateCommand<DBEntity> EditConnectDBCommand { get; set; }

        public DelegateCommand<TableEntity> SelectAllCommand { get; set; }

        public DelegateCommand<TableEntity> SelectTopCommand { get; set; }

        public DelegateCommand<TableEntity> SelectRunCommand { get; set; }

        public DelegateCommand<DataBaseEntity> CopyCommand { get; set; }

        public DelegateCommand<ViewEntity> ShowNewWindowCommand { get; set; }

        public DelegateCommand<DataBaseEntity> DeleteCommand { get; set; }
         

        public DelegateCommand<TableEntity> ExprotTableStructureCommand { get; set; }

        public DelegateCommand<DBEntity> RefreshCommand { get; set; }

        public DelegateCommand<TableEntity> AddDescriptionCommand { get; set; }

        public DelegateCommand<ProcEntity> ShowProcInfoCommand { get; set; }
         

        public DelegateCommand<TableEntity> TableDefinitionCommand { get; set; }

        public ObservableCollection<DataBaseEntity> DataSource
        {
            get => SysCache.ServerList;
            set
            {
                if (SysCache.ServerList != value)
                {
                    SysCache.ServerList = value;
                    this.RaisePropertyChanged();
                }
            }
        }

        private DataBaseEntity? _selectedItem;
        public DataBaseEntity? SelectedItem
        {
            get => _selectedItem;
            set
            {
                if (value != null && _selectedItem != value)
                {
                    _selectedItem = value;
                    this.SetProperty(ref _selectedItem, value);

                    RefreshRabbionMenuCanExecuteChanged();
                }
            }
        }


        public Action<TableEntity> ShowDescriptionWindows { get; set; }

        public Action<TableEntity> ShowTableDefinition { get; set; }

        public Action<DBEntity> ShowRegister { get; set; }


        public bool Connection()
        {
            if (SysCache.DBConnection == null)
            {
                WriteLog("当前连接不可用", 1);
                return false;
            }

            Task.Factory.StartNew(() =>
            {
                if (SysCache.ServerList != null)
                    DBOperatorFactory.GetOperator.CreateDBEntity(SysCache.ServerList, WriteLog, ApplicationExtension.InvokeOnUIThread);
            }).ContinueWith(delegate (Task t)
            {
                if (t.Exception != null)
                {
                    WriteLog(t.Exception.Message,1);
                }
                else
                {
                    WriteData();
                }
            });
            return true;
        }

        public void LoadData()
        {
            JsonDataBaseConverter jsonDataBaseConverter = new JsonDataBaseConverter(); 
            List<DataBaseEntity> list = DataCompression.DeserializeDataToFile<List<DataBaseEntity>>("data.dat", jsonDataBaseConverter);
            SysCache.ServerList = new ObservableCollection<DataBaseEntity>(list);

            foreach (DataBaseEntity server in SysCache.ServerList)
            {
                foreach (DataBaseEntity childNode in server.ChildNodes)
                {
                    if (childNode is DBEntity { Status: DBConnectStatus.Connected } dBEntity)
                    {
                        dBEntity.Status = DBConnectStatus.Off;
                        ChangeDBConnectionStatus(dBEntity);
                        break;
                    }
                }
            }
            this.RaisePropertyChanged(nameof(DataSource));
        }

        public void WriteData()
        {
            if (SysCache.ServerList != null)
            {
                List<DataBaseEntity> data = SysCache.ServerList.Select((entity) => entity.Copy()).ToList();

                JsonDataBaseConverter jsonDataBaseConverter = new JsonDataBaseConverter();
                data.SerializeDataToFile(AppDomain.CurrentDomain.BaseDirectory + "\\backupdata.dat", jsonDataBaseConverter);
                data.SerializeDataToFile(AppDomain.CurrentDomain.BaseDirectory + "\\data.dat", jsonDataBaseConverter);
                WriteLog("记录连接状态成功", 0);

                //发送通知 连接数据库操作
                _eventAggregator.SendMessage(new DBToolMessage
                {
                    Target = nameof(SqlContentViewModel),
                    ActionName = "ConnectToDb"
                });
            }
        }

        private void ChangeDBConnectionStatus(DBEntity? dbEntity)
        {
            if (dbEntity == null)
            {
                return;
            }

            if (SysCache.ServerList != null)
                foreach (DataBaseEntity server in SysCache.ServerList)
                {
                    if (server.ChildNodes != null)
                        foreach (DataBaseEntity? item in server.ChildNodes.Where(o => o.Name != dbEntity.Name))
                        {
                            if(item is DBEntity db)
                                db.Status = DBConnectStatus.Off;
                        }
                }

            dbEntity.Status = DBConnectStatus.Connected;
            if (dbEntity.ChildNodes is { Count: 0 })
            {
                if (!Connection())
                {
                    dbEntity.Status = DBConnectStatus.Off;
                }
            }
            else
            {
                dbEntity.IsExpanded = true;
                SelectedItem = dbEntity;
            } 
        }


        private void WriteSql(string? sql, SqlControlStatus status)
        {
            _eventAggregator.SendMessage(new DBToolMessage
            {
                Target = nameof(SqlContentViewModel),
                ActionName = "RunSql",
                Data = new SqlContentMessage() { Sql =sql,Status = status }
            }); 
        }

        private void WriteLog(string log, int isError)
        {
            _eventAggregator.SendLogMessage(log, isError == 1);
        }

    }


    public class JsonDataBaseConverter : JsonConverter<DataBaseEntity>
    {
        public override DataBaseEntity? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            var jsonDocument = JsonDocument.ParseValue(ref reader); 
            return GetDataBaseEntity(jsonDocument.RootElement);  
        }
        public override void Write(Utf8JsonWriter writer, DataBaseEntity value, JsonSerializerOptions options)
        {
            if(value is ServerEntity serverEntity)
            {
                JsonSerializer.Serialize(writer, serverEntity, options);
            }
            else if(value is DBEntity dbEntity)
            {
                JsonSerializer.Serialize(writer, dbEntity, options);
            } 
        }

        private DataBaseEntity? GetDataBaseEntity(JsonElement jsonElement)
        {
            string? imageUrl = jsonElement.GetProperty("ImageUrl").GetString();
            DataBaseEntity? dataBaseEntity = null;
            if (!string.IsNullOrEmpty(imageUrl))
            {
                if (imageUrl.Contains("computers.png"))
                {
                    dataBaseEntity = jsonElement.Deserialize<ServerEntity>();
                }
                else if (imageUrl.Contains("btnUnConnect.png"))
                {
                    dataBaseEntity = jsonElement.Deserialize<DBEntity>();
                }
            }
           
            if (dataBaseEntity != null)
            {
                dataBaseEntity.ChildNodes?.Clear();
                GetChildNodes(jsonElement, dataBaseEntity);
            }
            return dataBaseEntity;
        }

        private void GetChildNodes(JsonElement jsonElement, DataBaseEntity? dataBaseEntity)
        {
            if (dataBaseEntity == null)
                return;

            if (jsonElement.TryGetProperty("ChildNodes", out JsonElement childNodesElement))
            {
                foreach (JsonElement childNode in childNodesElement.EnumerateArray())
                {
                    DataBaseEntity? childEntity = GetDataBaseEntity(childNode);
                    if (childEntity != null)
                    {
                        dataBaseEntity.ChildNodes?.Add(childEntity);
                        GetChildNodes(childNode, childEntity);
                    }
                }
            }
        }
    }
}
